/*
 * Copyright 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview step 6 of the OAuth 2.0 client side flow tutorial.
 * @author silvano.luciani@gmail.com (Silvano Luciani)
 */

/**
 * If there is a valid token in the local storage sends a request to the API,
 * otherwise starts the authorization flow.
 */
function startFlow() {
  var localStorage = getStorage();
  var accessToken = localStorage.get('accessToken');

  var now = new goog.date.DateTime().getTime();
  if (accessToken && accessToken.expiration > now) {
    sendRequest(accessToken.access_token);
  } else {
    authorize();
  }
}

/**
 * If a fragment is present sends a validation request for the token, otherwise
 * redirects to the authorization server.
 */
function authorize() {
  var uri = new goog.Uri(window.location);
  if (uri.hasFragment()) {
    var queryData = new goog.Uri.QueryData(uri.getFragment());
    sendValidationRequest(queryData.get('access_token'));
  } else {
    redirectToAuth();
  }
}

/**
 * Redirects to the authorization server.
 */
function redirectToAuth() {
  var authUri = new goog.Uri(conf.AUTH_URI);
  authUri.setParameterValue('scope', conf.AUTH_SCOPE);
  authUri.setParameterValue('redirect_uri', conf.REDIRECT_URI);
  authUri.setParameterValue('response_type', 'token');
  authUri.setParameterValue('client_id', conf.CLIENT_ID);
  window.location = authUri.toString();
}

/**
 * Requests information about the received token using JSONP, then calls
 * processValidationResponse to validate the token.
 * @param {string} accessToken the value of the access token to validate.
 */
function sendValidationRequest(accessToken) {
  var reqUri = new goog.Uri(conf.TOKEN_INFO_URI);
  reqUri.setParameterValue('access_token', accessToken);
  var jsonp = new goog.net.Jsonp(reqUri);
  jsonp.send({}, function(response) {
    processValidationResponse(response, accessToken);
  });
}

/**
 * Discards the token and redirects to the authorization server if is invalid,
 * otherwise invokes sendRequest passing the valid access token.
 * @param {object} response the response of tokeninfo.
 * @param {string} accessToken the value of the access token to validate.
 */
function processValidationResponse(response, accessToken) {
  if (response.error == 'Invalid token' || response.audience != conf.CLIENT_ID) {
    redirectToAuth();
  } else {
    saveToken(accessToken, response.expires_in);
    sendRequest(accessToken);
  }
}

/**
 * Uses JSONP to send a request to the API.
 * @param {string} accessToken the value of the access token used to authorize
 *    the request.
 */
function sendRequest(accessToken) {
  var reqUri = new goog.Uri(conf.BASE_REQUEST_URI + 'adclients');
  reqUri.setParameterValue('access_token', accessToken);
  var jsonp = new goog.net.Jsonp(reqUri);
  jsonp.send({}, processResponse);
}

/**
 * Shows the list of ad clients.
 * @param {object} response the response received from the API.
 */
function processResponse(response) {
  var adClientsList = goog.dom.createElement('ul');
  for (var i in response.items) {
    var adClientElement = goog.dom.createElement('li');
    var adClientText = goog.dom.createTextNode(response.items[i].id);
    goog.dom.append(adClientElement, adClientText);
    goog.dom.append(adClientsList, adClientElement);
  }
  goog.dom.append(document.body, adClientsList);
}

/**
 * Creates the local storage.
 * @return {goog.storage.Storage} the local storage.
 */
function getStorage() {
  var mechanism = new goog.storage.mechanism.HTML5LocalStorage();
  var localStorage = new goog.storage.Storage(mechanism);
  return localStorage;
}

/**
 * Computes the expiration of the access token, then saves the access token.
 * @param {string} token contains the value of the access token.
 * @param {string} expires_in the validity of the token in seconds.
 */
function saveToken(token, expires_in) {
  var now = new goog.date.DateTime().getTime();
  var accessToken = {};
  var msToAdd = (parseInt(expires_in) - 100) * 1000;
  accessToken.expiration = now + msToAdd;
  accessToken.access_token = token;
  var localStorage = getStorage();
  localStorage.set('accessToken', accessToken);
}

